// Copyright  2004-2008 Backplane Ltd.
//
// This file is part of Ubiquity formsPlayer
//
// Ubiquity formsPlayer is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
//
// Ubiquity formsPlayer is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License
// along with Ubiquity formsPlayer If not, see <http://www.gnu.org/licenses/>.
//	
//
//   Purpose: implementation of CXFormsElementMessage.
//   $Id$


#include "stdafx.h"
#include "xformselementmessage.h"
#include "moveOutOfViewlink.h"

#include "dom3asls.h"
#include "UIImplRepository.h"
#include "XFormsApp.h"
#include <XBLEngine.h>
#include "messageDialog.h"
extern CXFormsApp theApp;


CXFormsElementMessage::CXFormsElementMessage(void)
:m_bDeferredBranding(false)
,m_bUseDialog(false)
{
}

CXFormsElementMessage::~CXFormsElementMessage(void)
{
	if(m_pEngine)
	{
		m_pEngine->Detach();
	}
}

HRESULT CXFormsElementMessage::render(void)
{
//	rebrand();

	CComQIPtr<IEventListener> pThisAsListener(this);
	CComBSTR sEvent(L"fp-message-hide");
	addEventListener(sEvent,pThisAsListener,false);
	sEvent = L"fp-message-show";
	addEventListener(sEvent,pThisAsListener,false);

	return S_OK;
}

HRESULT CXFormsElementMessage::handleEvent(IDOMEvent * pEvent)
{
	HRESULT hr = E_INVALIDARG;
	if(pEvent)
	{
		hr = S_FALSE;
		CImplActionMessage * pImplActionMessage = dynamic_cast<CImplActionMessage*>(m_pImpl);
		if(pImplActionMessage)
		{
			CComBSTR sEventName;
			pEvent->get_type(&sEventName);
			bool bHandled = false;
			if(false && sEventName == EVENT_ACTIVATE)
			{
				if(m_bUseDialog)
				{
					if(sEventName == EVENT_ACTIVATE)
					{
						bHandled = true;
						CMessageDialog d(m_sValue,false,true,m_pXForms);
					}
				}
				else
				{ 
						bHandled = true;
				}
			}
			else
			{
				if(sEventName == L"fp-message-hide")
				{
					if(m_pXForms->modalMessageActive())
					{
							CImplActionMessage::ELevels theLevel = pImplActionMessage->getLevel();
							if(theLevel == CImplActionMessage::ELevels::modal)
								hr = m_pXForms->deactivateModalMessage();
					}
					pImplActionMessage->m_bIsShowing = false;
					bHandled = true;
				}
				else if(sEventName == L"fp-message-show")
				{
					//rebrand();//I don't think this is needed?
					CImplActionMessage::ELevels theLevel = pImplActionMessage->getLevel();
					if(theLevel == CImplActionMessage::ELevels::modal)
					{
						m_pXForms->activateModalMessage();
						hr = S_OK;
					}
					bHandled = true;
				}
			}
			if(!bHandled)
			{
				__super::handleEvent(pEvent);
			}
		}
	}
	return hr;
}

STDMETHODIMP CXFormsElementMessage::Detach()
{

	if(m_pEngine)
	{
		m_pEngine->Detach();
		m_pEngine.Release();
	}
	CComQIPtr<IEventListener> pThisAsListener(this);
	if(pThisAsListener)
	{
		CComBSTR sEvent(L"fp-message-hide");
		removeEventListener(sEvent,pThisAsListener,false);
		sEvent = L"fp-message-show";
		removeEventListener(sEvent,pThisAsListener,false);

	}
	return 	__super::Detach();
}


HRESULT CXFormsElementMessage::DocumentReady()
{
	HRESULT hr = __super::DocumentReady();

//	if(SUCCEEDED(hr))
	if(!m_bUseDialog)
	{
		// Bug 321: xf:messages that are defined inside the first xf:model on a form
		//          will not have been able to retrieve the path to their branding image
		//          because they were instantiated too early. Hence, we will do it now.
		if(m_bDeferredBranding) {
			m_bDeferredBranding = false;
			//rebrand();
		}

		CComPtr<IHTMLElement> pEl;
		GetMasterElement(&pEl);
		if(pEl)
		{
			//Get an element to put the message into.
			//	This allows us to display multiple messages relatively
			//	inline, without upsetting the flow of the rest of the
			//	document;
			CComPtr<IHTMLDocument2> pDoc2;
			m_pXForms->GetOwnerDocument(&pDoc2);
			CComQIPtr<IHTMLDocument3> pDoc(pDoc2);

			if(pDoc)
			{
				CComPtr<IHTMLElement> pMessagesEl;
				CComBSTR sMessageStoreId(L"fp_messages");
				pDoc->getElementById(sMessageStoreId,&pMessagesEl);
				if(!pMessagesEl)
				{
					CComPtr<IHTMLElement> pBody;
					pDoc2->get_body(&pBody);
					CComBSTR sPosition(L"afterBegin");
					CComBSTR sDiv(L"<div id=\"fp_messages\" style=\"position:absolute;border:none;background-color:transparent;z-index:1000;top:0px;left:0px;visibility:hidden;\"></div>");
					pBody->insertAdjacentHTML(sPosition,sDiv);
					pDoc->getElementById(sMessageStoreId,&pMessagesEl);
				}
				CComQIPtr<IHTMLElement2> pMessagesEl2(pMessagesEl);
				CComBSTR sInsertLocation;
				//give modal messages a better zindex by putting them late in document order.
				CImplActionMessage * pImplActionMessage = dynamic_cast<CImplActionMessage*>(m_pImpl);
				if(pImplActionMessage)
				{
					CImplActionMessage::ELevels theLevel = pImplActionMessage->getLevel();
					if(theLevel == CImplActionMessage::ELevels::modal)
						sInsertLocation = L"beforeEnd";
					else
						sInsertLocation = L"afterBegin";

					//if m_bIsShowing is true at this point, then the event that causes the 
					// message to show has occurred before the message UI is available.
					//	but after the event has been registered for, 
					//	So show it!
					if(pImplActionMessage->m_bIsShowing)
					{
						CComQIPtr<IEventTarget> pEventTargetImpl = this;
						CComPtr<IDOMEvent> evt;
						hr = theApp.FormsManager().CreateDOMEvent(&evt);
						if(SUCCEEDED(hr) && evt) 
						{
							evt->initEvent(EVENT_ACTIVATE,FALSE,FALSE);
							BOOL bCancelled;
							hr = pEventTargetImpl->dispatchEvent(evt,&bCancelled);
						}

					}
				}
				else
					sInsertLocation = L"afterBegin";



				if(pMessagesEl2)
				{
					CComBSTR sDiv(L"div");
					CComPtr<IHTMLElement> pPEl;
					pMessagesEl2->insertAdjacentElement(sInsertLocation,pEl,0);
					pEl->get_parentElement(&pPEl);
			//		pPEl->get_outerHTML(&s);
					CComPtr<IHTMLElement> pMIPProxy;
					pDoc2->createElement(sDiv,&pMIPProxy);
					if(pMIPProxy)
					{
						//Insert the MIP proxy div into the messagecontainer.
						pMessagesEl2->insertAdjacentElement(sInsertLocation,pMIPProxy,0);
						//Insert the message into the MIP Proxy div.
						CComQIPtr<IHTMLElement2> pMIPProxy2(pMIPProxy);
						pMIPProxy2->insertAdjacentElement(sInsertLocation,pEl,0);
						
						//Set up the proxy relationship between the message container proxy and the 
						//	original containing element.
						//This is an ugly train of rightward pointing arrows, but it keeps the front and back ends a bit more separate
						//	rather than handing it to m_pFormControl->m_pParentImpl, and mixing it up.
						if(m_pImpl && m_pImpl->m_pParentImpl && m_pImpl->m_pParentImpl->m_pXFormsElement)
							m_pImpl->m_pParentImpl->m_pXFormsElement->put_MIPProxyElement(pMIPProxy);
					}
				}
			}
			//		MoveOutOfViewlink(pEl);
		}
	}
	return hr;
}



HRESULT CXFormsElementMessage::put_value(BSTR bsValue)
{
	HRESULT hr = S_OK;
	if(m_bUseDialog)
	{
		m_sValue.Empty();
		m_sValue = bsValue;
	}
	else
	{
		CComPtr<IHTMLElement> pEl;
		GetMasterElement(&pEl);
		pEl->put_innerHTML(bsValue);
		CComQIPtr<IHTMLElement3> pEl3 = pEl;
	//rebrand:
		rebrand();
	//fire the standard change event.
		VARIANT_BOOL bCancelled;
		CComPtr<IHTMLEventObj> pObj;
		CreateEventObject(&pObj);
		CComVariant vtObj(pObj);
		CComBSTR sOnAfterUpdate(L"onafterupdate");
		hr = pEl3->fireEvent(sOnAfterUpdate,&vtObj,&bCancelled);
	}
	return hr;
}


HRESULT CXFormsElementMessage::InitBehaviour()
{
	HRESULT hr =  __super::InitBehaviour();
	RegisterCustomEvents(sm_asEventNames,CXFORMSELEMENTMESSAGE_EVENTS_LENGTH, m_alEventCookies);

	return hr;
}


void CXFormsElementMessage::rebrand(void)
{
	CImplActionMessage::ELevels theLevel = dynamic_cast<CImplActionMessage*>(m_pImpl)->getLevel();
	if(m_pXForms && theLevel != CImplActionMessage::ELevels::ephemeral)// && theLevel != CImplActionMessage::ELevels::modal)
	{
		if(m_pXForms->m_XFConfig.Initialised() == false)  // Bug 321
			m_bDeferredBranding = true;
		else if(m_pXForms->m_XFConfig.MessageBranding() == true) {  // Bug 372: Allow message branding to be disabled.
			CComPtr<IHTMLElement> pMaster;
			HRESULT hr = GetMasterElement(&pMaster);
			if (pMaster)
			{
				//TODO: move to another object from which this inherits, or attach as separate behaviour.
				if(!m_pBrandingImage)
				{
					IDispatchPtr pDisp;
					pMaster->get_document(&pDisp);
					if(pDisp)
					{
						CComQIPtr<IHTMLDocument2> pDoc2 = pDisp;
						if(pDoc2)
						{
							CComPtr<IHTMLWindow2> pWin2;
							pDoc2->get_parentWindow(&pWin2);
							if(pWin2)
							{
								CComPtr<IHTMLImageElementFactory> pImgFac;
								pWin2->get_Image(&pImgFac);
								if(pImgFac)
								{
									CComVariant vtEmpty;
									pImgFac->create(vtEmpty,vtEmpty,&m_pBrandingImage);
								}
							}
						}

					}
				}
				if(m_pBrandingImage)
				{
					CComBSTR bsBrandingImageSrc;
					bsBrandingImageSrc.Attach(m_pXForms->m_XFConfig.MessageLogo());
					m_pBrandingImage->put_src(bsBrandingImageSrc);
					CComQIPtr<IHTMLElement2> pEl2 = pMaster;
					CComQIPtr<IHTMLElement> pEl = m_pBrandingImage;
					pEl2->insertAdjacentElement(CComBSTR(L"afterBegin"), pEl, 0);
					CComPtr<IHTMLStyle> pStyle;
					pEl->get_style(&pStyle);
					pStyle->put_display(CComBSTR(L"block")); 
				}
			}
		}
	}
}